# pragma once

# include <iterator>
# include <cassert>
# include <vector>

# include <iostream>

namespace utils {

  namespace details {
  class iterator : public std::iterator<std::bidirectional_iterator_tag, size_t> {
  public:

    iterator(size_t pos) throw() : position_(pos) {}

    iterator& operator++() throw () {
      position_++;
      return *this;
    }

    iterator operator++(int) const throw() {
      return iterator(position_ + 1);
    }

    bool operator==(iterator const& it) const throw() {
      return position_ == it.position_;
    }

    bool operator!=(iterator const& it) const throw() {
      return position_ != it.position_;
    }

    size_t operator*() const throw() {
      return position_;
    }

  private:

    size_t position_;

  };

  }

  class range {
  public:
    typedef details::iterator iterator;
  public:

    range(size_t b, size_t e) throw() : begin_(b), end_(e) {
      assert(begin_ <= end_);
    }

    range operator()(size_t beginOffset) const throw() {
      assert(begin_ + beginOffset < end_);
      return range(begin_ + beginOffset, end_);
    }

    range operator()(size_t bOffset, int eOffset) const throw() {
//      assert(begin_ + bOffset < end_);
//      assert(eOffset < 0);
//      assert(end_ + eOffset >= 0);
  
      if (eOffset > 0) {
        assert(eOffset > bOffset);
        return range(begin_ + bOffset, begin_ + eOffset);
      } else
        return range(begin_ + bOffset, end_ + eOffset);
    }

  
    size_t operator[](int const index) const throw() {
      if (index > 0) {
        assert(begin_ + index < end_);
        return begin_ + index;
      } else {
        assert(end_ + index > begin_);
        return end_ + index;
      }
    }

    size_t size() const throw() {
      return end_ - begin_;
    }

    iterator begin() const throw() {
      return iterator(begin_);
    }

    iterator end() const throw() {
      return iterator(end_);
    }

  private:

    size_t const begin_;
    size_t const end_;

  };

  range::iterator begin(range const& r) throw() {
    return r.begin();
  }

  range::iterator end(range const& r) throw() {
    return r.end();
  }


  template <typename T>
  class Slice {
  public:
    typedef typename std::vector<T>::const_iterator iterator;
  public:

    Slice(std::vector<T> const& v) throw() 
        : begin_(v.begin()), end_(v.end()) {}

    Slice(iterator b, iterator e) throw() 
        : begin_(b), end_(e) {
      assert(e - b >= 0);
    }

    Slice operator()(int bOffset) const throw() {
      assert(end_ - begin_ - bOffset >= 0);
      return Slice(begin_ + bOffset, end_);
    }

    Slice operator() (int bOffset, int eOffset) const throw() {
      assert(end_ + eOffset - begin_ - bOffset >= 0);
      return Slice(begin_ + bOffset, end_ + eOffset);
    }

    T operator[](int index) const throw() {
      if (index > 0)
        return *(begin_ + index);
      else
        return *(end_+index);
    }

    size_t size() const throw() {
      return end_ - begin_;
    }

    iterator begin() const throw() { return begin_; }
    iterator end() const throw() { return end_; }

  private:
    iterator begin_;
    iterator end_;

  };

  template <typename T>
  typename Slice<T>::iterator begin(Slice<T> const& s) throw () {
    return s.begin();
  }

  template <typename T>
  typename Slice<T>::iterator end(Slice<T> const& s) throw() {
    return s.end();
  }

}
